﻿#region Description
/*  File Name:      MERenderComponent.cs
 *  Author:         Adam Goodchild
 *  
 *  Description:    A Render Component allows an Entity to render something to the Screen.
*/
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MinimizeEngine.Entities;
using MinimizeEngine.Managers;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MinimizeEngine.Entities.Primitives;
#endregion

namespace MinimizeEngine.Components.Render
{

    #region Enum

    //public enum PrimitiveShape
    //{
    //    Cube,
    //    Sphere,
    //}

    #endregion
    /// <summary>
    /// Allows an Entity to Render something to the Screen.
    /// </summary>
    public class MEPrimitiveRenderComponent : MEBaseComponent
    {
        #region Fields

        /// <summary>
        /// Render Components Model
        /// </summary>
        private MEBasePrimitive mPrimitive;

        /// <summary>
        /// Scale information for the Render Component
        /// </summary>
        private Matrix mScaleMatrix;

        /// <summary>
        /// World Matrix for the Render Component
        /// </summary>
        private Matrix mWorldTransformMatrix;

        /// <summary>
        /// Primitive Shapes Basic Effect
        /// </summary>
        private BasicEffect mBasicEffect;

        #endregion

        #region Properties

        /// <summary>
        /// The Render Components Model
        /// </summary>
        public MEBasePrimitive Primitive
        {
            get { return mPrimitive; }
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Construct a new Render COmponent
        /// </summary>
        /// <param name="parent">Entity this will be attached to</param>
        /// <param name="modelPath">Path of the Model to be loaded</param>
        public MEPrimitiveRenderComponent(MEBaseEntity parent, PrimitiveShape shape) : base(parent)
        {
            //switch (shape)
            //{
            //case PrimitiveShape.Cube:
            //        mPrimitive = new MECube(parent.Scale);
            //    break;
            //case PrimitiveShape.Sphere:
            //    break;
            //}

            ////Create the Basic Effect for the Primitive Shape
            //mBasicEffect = new BasicEffect(MEEngineManager.DeviceManager.GraphicsDevice, null);
        }

        /// <summary>
        /// Initialize the Render Component
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            mScaleMatrix = Matrix.CreateScale(Parent.Scale);
            mWorldTransformMatrix = mScaleMatrix * Parent.Rotation * Matrix.CreateTranslation(Parent.Position);
        }

        #endregion

        #region Update

        /// <summary>
        /// Update the Primitive Render Component
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            mWorldTransformMatrix = mScaleMatrix * Parent.Rotation * Matrix.CreateTranslation(Parent.Position);
        }

        #endregion

        #region Draw

        /// <summary>
        /// Draw the Primitive Shape Component
        /// </summary>
        public override void Draw()
        {
            mBasicEffect.World = mWorldTransformMatrix;
            mBasicEffect.View = MECameraManager.mActiveCamera.Parent.View;
            mBasicEffect.Projection = MECameraManager.mActiveCamera.Parent.Projection;
            mBasicEffect.EnableDefaultLighting();
            mBasicEffect.PreferPerPixelLighting = true;
            mBasicEffect.DiffuseColor = Color.Gray.ToVector3();
            mBasicEffect.Alpha = Color.Gray.A / 255.0f;

            //Set Render States
            RenderState renderState = mBasicEffect.GraphicsDevice.RenderState;
            renderState.AlphaTestEnable = false;
            renderState.DepthBufferEnable = true;
            renderState.DepthBufferFunction = CompareFunction.LessEqual;

            if (Color.Gray.A < 255)
            {
                //Set the Render State for Alpha Blended Rendering
                renderState.AlphaBlendEnable = true;
                renderState.AlphaBlendOperation = BlendFunction.Add;
                renderState.SourceBlend = Blend.SourceAlpha;
                renderState.DestinationBlend = Blend.InverseSourceAlpha;
                renderState.SeparateAlphaBlendEnabled = false;
                renderState.DepthBufferWriteEnable = false;
            }
            else
            {
                //Set the Render State for Opaque Rendering
                renderState.AlphaBlendEnable = false;
                renderState.DepthBufferWriteEnable = true;
            }

            //Now we Draw the Primitive Shape
            GraphicsDevice device = mBasicEffect.GraphicsDevice;
            device.VertexDeclaration = mPrimitive.VertexDeclaration;
            device.Vertices[0].SetSource(mPrimitive.VertexBuffer, 0, VertexPositionNormal.mSizeInBytes);
            device.Indices = mPrimitive.IndexBuffer;

            mBasicEffect.Begin();

            foreach (EffectPass pass in mBasicEffect.CurrentTechnique.Passes)
            {
                pass.Begin();

                int primitiveCount = mPrimitive.Indices.Count / 3;

                device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, mPrimitive.Vertices.Count, 0, primitiveCount);

                pass.End();
            }

            mBasicEffect.End();
        }

        #endregion
    }
}
